<template>
  <div class="content">
    <h1 class="seo-title">在线文本工具 - JSON格式化, XML格式化等</h1>
    <div class="content-bar">
      <div class="tool-bar">
      <button class="bar-btn" @click="demo">来个Demo</button>
      <button class="bar-btn" @click="jsonFormat">JSON格式化</button>
      <button class="bar-btn" @click="xmlFormat">XML格式化</button>
      <button class="bar-btn" @click="addDoubleQuta">+双引号</button>
      <button class="bar-btn" @click="addSingleQuta">+单引号</button>
      <button class="bar-btn" @click="addComma">+逗号</button>
      <button class="bar-btn" @click="delLeft">向前删除1个</button>
      <button class="bar-btn" @click="delRight">向后删除1个</button>
      <button class="bar-btn" @click="delEmpty">去前后空格</button>
      <button class="bar-btn" @click="delAllEmpty">去所有空格</button>
      <button class="bar-btn" @click="delEmptyLine">删除空行</button>
      <button class="bar-btn" @click="delSame">去重</button>
      <button class="bar-btn" @click="group(',')">逗号合并</button>
      <button class="bar-btn" @click="group('')">空格合并</button>
      <button class="bar-btn" @click="splitLines">逗号分割</button>
      <button class="bar-btn" @click="copy">复制</button>
      <button class="bar-btn" @click="clean">清除</button>
    </div>
    <div class="tool-bar">
      <button class="bar-btn" @click="urlEncode">URL编码</button>
      <button class="bar-btn" @click="urlDecode">URL解码</button>
      <button class="bar-btn" @click="base64Encode">Base64编码</button>
      <button class="bar-btn" @click="base64Decode">Base64解码</button>
      <button class="bar-btn" @click="gmd5">md5加密</button>
      <button class="bar-btn" @click="toUp">转大写</button>
      <button class="bar-btn" @click="toLow">转小写</button>

      <span class="text-title">分栏提取:</span>
      <select v-model="colSplit">
        <option value=",">逗号</option>
        <option value=" ">空格</option>
        <option value="	">tab</option>
        <option value="_">下划线</option>
        <option value="-">-</option>
        <option value=".">.</option>
        <option value="%">%</option>
      </select>
      <span class="text-title">第</span>
      <input type="number" v-model="colNum" class="input-group-num-min" placeholder="列数"/>
      <span class="text-title">列</span>
      <button class="bar-btn text-title" @click="fetchCol">提取</button>

      <span class="text-title">随机生成</span>
      <input type="number" v-model="strNum" class="input-group-num-min" placeholder="个数"/>
      <input type="number" v-model="strLength" class="input-group-num" placeholder="长度"/>
      <button class="bar-btn text-title" @click="randomStr">生成字符串</button>
    </div>
    </div>
    <div class="text-content">
      <Codemirror
        class="input-editor"
        v-model:value="origin"
        border
        height="680"
        width="640"
      >
      </Codemirror>
      <button class="bar-btn btn-copy-to" @click="copyTo"><<</button>
      <Codemirror
        class="output-editor"
        v-model:value="retsult"
        border
        :options="cmRef" 
        height="680"
        width="640"
      >
      </Codemirror>
    </div>
    <div class="tool-bar">
      <p class="error-msg">{{ errorMsg }}</p>
    </div>
    <div>
      <button class="bar-btn text-title" @click="toggle">切换模式</button>
      <span class="text-title">模式:</span>
      <span class="text-model">{{ modelFlag===1?"单步":"多步" }} </span>
      <span class="text-title">分组数:</span>
      <input type="number" v-model="groupNum" class="input-group-num" placeholder="分组数"/>
    </div>
  </div>

</template>

<script>
  import { useHead } from '@vueuse/head'
  import { InstallCodemirro } from "codemirror-editor-vue3"
  import "codemirror/mode/javascript/javascript.js"
  import "codemirror/mode/xml/xml.js"
 
  import Codemirror from "codemirror-editor-vue3"
  import CryptoJS from 'crypto-js';

  export default {
    components: { Codemirror },
    setup() {
      // ... 其余的 setup 逻辑
    },
    data () {
      return {
        origin: "",
        retsult: "",
        groupNum: 10,
        modelFlag: 2,
        colNum: 1,
        colSplit: ',',
        strNum: 1,
        strLength: 32,
        errorMsg: '',
        shift: [],
        cmRef: {
          mode: "application/json"
        }
      }
    },
    mounted() {
      // window.location.pathname = '/';
      this.init()
    },
    methods: {
      init() {
        this.shift = ['\n'];
        for(var ix=0;ix<100;ix++){
          this.shift.push(this.shift[ix]+'    ');
        }
      },
      cleanError() {
        this.errorMsg = ""
      },
      demo() {
        this.event('demo')
        this.origin = ""
        this.retsult = ""
        this.cleanError()

        this.origin = `{"name": "ueg", "value": "hello world", "age": 20}`
      },
      isEmpty(str) {
        if (str && str!== null && str!== undefined && str.trim()!== '') {  
          return false
        } else {  
          return true
        }  
      },
      jsonFormat() {
        this.event('json')
        this.cleanError()
        let str;
        if (this.modelFlag === 2 && !this.isEmpty(this.retsult)) {
          str = this.retsult
        } else {
          str = this.origin
        }
        try {
          this.retsult = JSON.stringify(JSON.parse(str), null, 4)
          this.cmRef = {
            mode: "application/json"
          }
        } catch (error) {
          this.errorMsg = error
          console.log('json format error', error)
        }
      },
      xmlFormat() {
        this.event('A1')
        this.cleanError()
        let str;
        if (this.modelFlag === 2 && !this.isEmpty(this.retsult)) {
          str = this.retsult
        } else {
          str = this.origin
        }

        try {
          this.retsult = this.xmlFormatString(str)
          this.cmRef = {
            mode: "application/xml"
          }
        } catch (error) {
          this.errorMsg = error
          console.log('xml format error', error)
        }
      },
      xmlFormatString(text) {
        var ar = text.replace(/>\s{0,}</g,"><") .replace(/</g,"~::~<").replace(/\s*xmlns\:/g,"~::~xmlns:") .replace(/\s*xmlns\=/g,"~::~xmlns=").split('~::~'),
        len = ar.length,
        inComment = false,
        deep = 0,
        str = '',
        ix = 0;

        for(ix=0;ix<len;ix++) {
          // start comment or <![CDATA[...]]> or <!DOCTYPE //
          if(ar[ix].search(/<!/) > -1) {
            str += this.shift[deep]+ar[ix];
            inComment = true;
            // end comment  or <![CDATA[...]]> //
            if(ar[ix].search(/-->/) > -1 || ar[ix].search(/\]>/) > -1 || ar[ix].search(/!DOCTYPE/) > -1 ) {
              inComment = false;
            }
          } else
          // end comment  or <![CDATA[...]]> //
          if(ar[ix].search(/-->/) > -1 || ar[ix].search(/\]>/) > -1) {
            str += ar[ix];
            inComment = false;
          } else
          // <elm></elm> //
          if( /^<\w/.exec(ar[ix-1]) && /^<\/\w/.exec(ar[ix]) &&
            /^<[\w:\-\.\,]+/.exec(ar[ix-1]) == /^<\/[\w:\-\.\,]+/.exec(ar[ix])[0].replace('/','')) {
            str += ar[ix];
            if(!inComment) deep--;
          } else
          // <elm> //
          if(ar[ix].search(/<\w/) > -1 && ar[ix].search(/<\//) == -1 && ar[ix].search(/\/>/) == -1 ) {
            str = !inComment ? str += this.shift[deep++]+ar[ix] : str += ar[ix];
          } else
          // <elm>...</elm> //
          if(ar[ix].search(/<\w/) > -1 && ar[ix].search(/<\//) > -1) {
            str = !inComment ? str += this.shift[deep]+ar[ix] : str += ar[ix];
          } else
          // </elm> //
          if(ar[ix].search(/<\//) > -1) {
            str = !inComment ? str += this.shift[--deep]+ar[ix] : str += ar[ix];
          } else
          // <elm/> //
          if(ar[ix].search(/\/>/) > -1 ) {
            str = !inComment ? str += this.shift[deep]+ar[ix] : str += ar[ix];
          } else
          // <? xml ... ?> //
          if(ar[ix].search(/<\?/) > -1) {
            str += this.shift[deep]+ar[ix];
          } else
          // xmlns //
          if( ar[ix].search(/xmlns\:/) > -1  || ar[ix].search(/xmlns\=/) > -1) {
            str += this.shift[deep]+ar[ix];
          }

          else {
            str += ar[ix];
          }
        }

        return  (str[0] == '\n') ? str.slice(1) : str;

      },
      addSingleQuta() {
        this.event('addSingleQuta')
        this.addQuta("'")
      },
      addDoubleQuta() {
        this.event('addDoubleQuta')
        this.addQuta("\"")
      },
      toggle() {
        this.event('toggle')
        this.modelFlag = (this.modelFlag === 1? 2 : 1)
      },
      randomStr() {
        this.cleanError()
        let strNum = this.strNum; // specify the number of strings to generate
        let strLength = this.strLength; // specify the length of each string
        let randomStr = '';
        let characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
        for(let i = 0; i < strNum; i++){
          for(let j = 0; j < strLength; j++){
            randomStr += characters.charAt(Math.floor(Math.random() * characters.length));
          }
          randomStr += '\n';
        }
        this.retsult = randomStr;
      },
      urlEncode() {
        this.event('urlEncode')
        this.cleanError()
        let str;
        if (this.modelFlag === 2 && !this.isEmpty(this.retsult)) {
          str = this.retsult
        } else {
          str = this.origin
        }
        this.retsult = encodeURIComponent(str)
      },
      urlDecode() {
        this.event('urlDecode')
        this.cleanError()
        let str;
        if (this.modelFlag === 2 && !this.isEmpty(this.retsult)) {
          str = this.retsult
        } else {
          str = this.origin
        }
        this.retsult = decodeURIComponent(str)
      },
      base64Encode() {
        this.event('base64Encode')
        this.cleanError()
        let str;
        if (this.modelFlag === 2 && !this.isEmpty(this.retsult)) {
          str = this.retsult
        } else {
          str = this.origin
        }
        this.retsult = btoa(str)
      },
      base64Decode() {
        this.event('base64Decode')
        this.cleanError()
        let str;
        if (this.modelFlag === 2 && !this.isEmpty(this.retsult)) {
          str = this.retsult
        } else {
          str = this.origin
        }
        try {
          this.retsult = atob(str)
        } catch (error) {
          console.log('decode error', error)
        }
      },
      gmd5() {
        this.event('gmd5')
        this.cleanError()
        let lines;
        if (this.modelFlag === 2 && !this.isEmpty(this.retsult)) {
          lines = this.retsult.split("\n")
        } else {
          lines = this.origin.split("\n")
        }

        this.retsult = ""
        let first = true
        for (let line of lines) {
          if (first) {
            first = false
          } else {
            this.retsult += '\n'
          }

          if (!this.isEmpty(line)) {
            this.retsult += CryptoJS.MD5(line)
          }
        }

      },
      toUp() {
        this.event('toUp')
        this.cleanError()
        let str;
        if (this.modelFlag === 2 && !this.isEmpty(this.retsult)) {
          str = this.retsult
        } else {
          str = this.origin
        }

        this.retsult = str.toUpperCase()
      },
      toLow() {
        this.event('toLow')
        this.cleanError()
        let str;
        if (this.modelFlag === 2 && !this.isEmpty(this.retsult)) {
          str = this.retsult
        } else {
          str = this.origin
        }

        this.retsult = str.toLowerCase()
      },
      fetchCol() {
        this.event('fetchCol')
        this.cleanError()
        let lines;
        if (this.modelFlag === 2 && !this.isEmpty(this.retsult)) {
          lines = this.retsult.split("\n")
        } else {
          lines = this.origin.split("\n")
        }
        let first = true
        this.retsult = ""
        for (let line of lines) {
          console.log('line', line)
          let cols = line.split(this.colSplit)
          console.log('split to', cols)
          if (first) {
            first = false
          } else {
            this.retsult += '\n'
          }

          if (this.colNum > cols.length) {
            continue
          } else {
            this.retsult += `${cols[this.colNum-1]}`
          }
        }
      },
      addQuta(smbol) {
        this.cleanError()
        let lines;
        if (this.modelFlag === 2 && !this.isEmpty(this.retsult)) {
          lines = this.retsult.split("\n")
        } else {
          lines = this.origin.split("\n")
        }

        this.retsult = ""
        let first = true
        for (let line of lines) {
          if (first) {
            first = false
            this.retsult += `${smbol}${line}${smbol}`
          } else {
            this.retsult += `\n${smbol}${line}${smbol}`
          }
        }

      },
      addComma() {
        this.event('addComma')
        this.cleanError()
        let lines;
        if (this.modelFlag === 2 && !this.isEmpty(this.retsult)) {
          lines = this.retsult.split("\n")
        } else {
          lines = this.origin.split("\n")
        }
        
        this.retsult = ""
        let first = true
        for (let line of lines) {
          if (first) {
            first = false
            this.retsult += `${line},`
          } else {
            this.retsult += `\n${line},`
          }
        }
      },
      delLeft() { 
        this.event('delLeft')
        this.cleanError()
        let lines
        if (this.modelFlag === 2 && !this.isEmpty(this.retsult)) {
          lines = this.retsult.split("\n")
        } else {
          lines = this.origin.split("\n")
        }

        this.retsult = ""
        let first = true
        for (let line of lines) {
          if (first) {
            first = false
            this.retsult += line.slice(1)
          } else {
            this.retsult += `\n${line.slice(1)}`
          }
        }
      },
      delRight() {
        this.event('delRight')
        this.cleanError()
        let lines
        if (this.modelFlag === 2 && !this.isEmpty(this.retsult)) {
          lines = this.retsult.split("\n")
        } else {
          lines = this.origin.split("\n")
        }

        this.retsult = ""
        let first = true
        for (let line of lines) {
          if (first) {
            first = false
            this.retsult += line.slice(0, -1)
          } else {
            this.retsult += `\n${line.slice(0, -1)}`
          }
        }
      },
      delAllEmpty() {
        this.event('delAllEmpty')
        this.cleanError()
        let lines
        if (this.modelFlag === 2 && !this.isEmpty(this.retsult)) {
          lines = this.retsult.split("\n")
        } else {
          lines = this.origin.split("\n")
        }

        this.retsult = ""
        let first = true
        for (let line of lines) {
          if (first) {
            first = false
            this.retsult += line.replace(/\s/g, "")
          } else {
            this.retsult += `\n${line.replace(/\s/g, "")}`
          }
        }
      },
      delEmpty() {
        this.event('delEmpty')
        this.cleanError()
        let lines
        if (this.modelFlag === 2 && !this.isEmpty(this.retsult)) {
          lines = this.retsult.split("\n")
        } else {
          lines = this.origin.split("\n")
        }

        this.retsult = ""
        let first = true
        for (let line of lines) {
          if (first) {
            first = false
            this.retsult += line.trim()
          } else {
            this.retsult += `\n${line.trim()}`
          }
        }
      },
      delEmptyLine() {
        this.event('delEmptyLine')
        this.cleanError()
        let lines
        if (this.modelFlag === 2 && !this.isEmpty(this.retsult)) {
          lines = this.retsult.split("\n")
        } else {
          lines = this.origin.split("\n")
        }

        this.retsult = ""
        let first = true
        for (let line of lines) {
          if (line.trim()!= "") {
            if (first) {
              first = false
              this.retsult += line
            } else {
              this.retsult += `\n${line}`
            }
          }
        }
      },
      delSame() {
        this.event('delSame')
        this.cleanError()
        let lines
        if (this.modelFlag === 2 && !this.isEmpty(this.retsult)) {
          lines = this.retsult.split("\n")
        } else {
          lines = this.origin.split("\n")
        }

        this.retsult = ""
        let first = true
        let set = new Set()
        for (let line of lines) {
          if (set.has(line)) {
            continue
          }
          set.add(line)
          if (first) {
            first = false
            this.retsult += line
          } else {
            this.retsult += `\n${line}`
          }
        }
      },
      copy() {
        this.event('copy')
        this.cleanError()
        const textarea = document.createElement("textarea");
        textarea.value = this.retsult;
        document.body.appendChild(textarea);
        textarea.select();
        document.execCommand('copy');
        document.body.removeChild(textarea);
        // alert("复制成功");
      },
      copyTo() {
        this.cleanError()
        this.origin = this.retsult
      },
      clean() {
        this.event('clean')
        this.origin = ""
        this.retsult = ""
        this.cleanError()
      },
      splitLines() {
        this.cleanError()
        if (this.modelFlag === 2 && !this.isEmpty(this.retsult)) {
          this.retsult = this.retsult.split(",").join("\n")
        } else {
          this.retsult = this.origin.split(",").join("\n")
        }
      },
      group(sp) {
        this.event('group')
        this.cleanError()
        let lines
        if (this.modelFlag === 2 && !this.isEmpty(this.retsult)) {
          lines = this.retsult.split("\n")
        } else {
          lines = this.origin.split("\n")
        }

        this.retsult = ""
        let first = true
        if (this.groupNum <= 0) {
          this.groupNum = 10
        }

        let index = 0
        for (let line of lines) {
          index++
          if (first) {
            first = false
            this.retsult += `${line}`
          } else {
            this.retsult += `${sp} ${line}`
          }

          if (index >= this.groupNum) {
            index = 0
            first = true
            this.retsult += "\n"
          }
        }
      },
      event(act) {
        try {
          LA.track(act);
        } catch (e) {
          console.log(e)
        }
      }
    }
  }

</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>

.input-editor,.output-editor { 
  margin: 4px;
  text-align: left;
}
.tool-bar { 
  text-align: left;
  margin: 2px auto;
  width: 1324px;
}


.bar-btn {
  margin-right: 4px;
  color: #333;
}
.btn-copy-to {
  margin: 0px;
}
.content {
  text-align: center;
}

.text-content {
  display: flex;
  justify-content: center;
  align-items: center;
}

.text-title {
  color: #333;
  margin-left: 4px;
  font-size: 12px;

}
.text-model {
  color: white;
  background-color: #333;
  font-weight: 600;
  font-size: 14px;
  padding-left: 2px;
  padding-right: 2px;

}
.input-group-num {
  width: 40px;
  margin-left: 2px;
  margin-top: 0px;
}

.input-group-num-min {
  width: 30px;
  margin-left: 2px;
  margin-top: 0px;
}

.error-msg {
  color: red;
}

.seo-title {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
</style>